import ast
import logging

logging.basicConfig(level=logging.INFO)


class AST操作基类:
    def __init__(self, ast树):
        self.ast树 = ast树
        self.操作日志 = []

    def 获取节点2(self, 路径):

        节点 = self.ast树
        for 部分 in 路径:
            if 部分=="Module":
                节点 = 节点.body
                continue
            if isinstance(部分, int):
                节点 = 节点[部分]
            else:
                节点 = getattr(节点, 部分)
        return 节点

    def 获取节点(self, 路径):
        节点 = self.ast树
        try:
            for 部分 in 路径:
                if 部分 == "Module":
                    节点 = 节点.body
                    continue
                if isinstance(部分, int):
                    节点 = 节点[部分]
                else:
                    节点 = getattr(节点, 部分)
        except (AttributeError, IndexError, TypeError):
            return None  # 获取节点失败，返回 None
        return 节点

    def 修改节点(self, 路径, 新值):
        父节点 = self.获取节点(路径[:-1])
        最后一步骤 = 路径[-1]
        if isinstance(父节点, ast.AST):
            setattr(父节点, 最后一步骤, 新值)
        elif isinstance(父节点, list):
            父节点[最后一步骤] = 新值
        else:
            self.记录错误("修改节点操作只能在AST节点或列表中进行")
            raise TypeError("修改节点操作只能在AST节点或列表中进行")

    def 生成路径(self, 变量名, 当前节点=None, 当前路径=None, 路径列表=None):
        """
        生成AST树中目标节点的路径，支持遍历多个匹配路径。
        :param 变量名: 要查找的变量名
        :param 当前节点: 当前遍历的AST节点，默认从根节点开始
        :param 当前路径: 当前节点的路径
        :param 路径列表: 用于保存所有找到的路径
        :return: 包含所有匹配路径的列表
        """
        if 当前路径 is None:
            当前路径 = []
        if 当前节点 is None:
            当前节点 = self.ast树
        if 路径列表 is None:
            路径列表 = []
        if isinstance(当前节点, ast.Name):
            if isinstance(当前节点.ctx, ast.Store) and 当前节点.id == 变量名:
                路径列表.append(当前路径)
        # 处理AST对象，遍历其字段
        if isinstance(当前节点, ast.AST):
            for field, value in ast.iter_fields(当前节点):
                if isinstance(value, list):
                    # 处理列表中的AST节点
                    for index, item in enumerate(value):
                        if isinstance(item, ast.AST):
                            # 递归调用生成路径，确保每次递归时路径是独立的
                            self.生成路径(变量名, item, 当前路径 + [field, index], 路径列表)

                elif isinstance(value, ast.AST):
                    # 递归调用生成路径，确保路径正确添加
                    self.生成路径(变量名, value, 当前路径 + [field], 路径列表)

        return 路径列表
    def 插入节点(self, 路径, 新节点, 位置=None):
        父节点 = self.获取节点(路径)
        print("插入节点",路径)
        print("父节点",父节点)

        if isinstance(父节点, list):
            if 位置:
                父节点.insert(位置, 新节点)
            else:
                父节点.append(新节点)
        else:
            self.记录错误("插入节点操作只能在列表中进行")
            raise TypeError("插入节点操作只能在列表中进行")
        return len(父节点)-1

    def 删除节点(self, 路径, 位置=None):
        print("删除节点",路径)
        父节点 = self.获取节点(路径[:-1])
        if 位置 is None:
            位置=路径[-1]
        最后一步骤 = 路径[-1]
        if isinstance(父节点, list):
            print("位置",位置)
            父节点.pop(位置)
        elif hasattr(父节点, 最后一步骤) and isinstance(getattr(父节点, 最后一步骤), list):
            getattr(父节点, 最后一步骤).pop(位置)
        else:
            self.记录错误("删除节点操作只能在列表中进行")
            raise TypeError("删除节点操作只能在列表中进行")

    def 记录错误(self, 消息):
        logging.error(消息)
        self.操作日志.append(("错误", 消息))

    def 记录操作(self, 消息):
        logging.info(消息)
        self.操作日志.append(("操作", 消息))

    def 优化_ast(self):
        for node in ast.walk(self.ast树):
            if isinstance(node, ast.Import):
                for alias in node.names:
                    if not self.变量是否使用(alias.name):
                        self.删除节点(['body'], self.ast树.body.index(node))

    def 变量是否使用(self, 变量名):
        for node in ast.walk(self.ast树):
            if isinstance(node, ast.Name) and node.id == 变量名:
                return True
        return False

    def 替换节点(self, 路径, 新节点):
        父节点 = self.获取节点(路径[:-1])
        最后一步骤 = 路径[-1]
        if isinstance(父节点, list):
            父节点[最后一步骤] = 新节点
        elif hasattr(父节点, 最后一步骤):
            setattr(父节点, 最后一步骤, 新节点)
        else:
            self.记录错误("替换节点操作只能在AST节点或列表中进行")
            raise TypeError("替换节点操作只能在AST节点或列表中进行")

